import {App, MarkdownView, Modal, Notice, Plugin, PluginSettingTab, Setting, TFile, TFolder, Vault} from "obsidian";
import HeadingSuggest from "./suggest/heading-suggest";
import {stripLeft} from "./utils";
import {RenamingUI} from "./ui";

interface PluginSettings {
    isAutosuggestEnabled: boolean,
    autocompleteTriggerPhrase: string,
    vaultStartLocation: string,
    ingoredHeaders: Array<string>,
    ignoredSuffixArray: Array<string>,
    // headers: Array<[string, string, string, string, boolean]>,
    // locations: Array<string>,
    // outputs: Array<string>,
    // enables: Array<string>,
    // populateEmptyTitle: boolean,
    // titleLinks: boolean,
}

const DEFAULT_SETTINGS: PluginSettings = {
    isAutosuggestEnabled: true,
    autocompleteTriggerPhrase: "# ",
    vaultStartLocation: "1_Inbox/Diary",
    ingoredHeaders: ["## 🕓今日事项", "## ✒️日常笔记", "## 🔔待办提醒", "## ✏思考总结"],
    ignoredSuffixArray: [".excalidraw.md"],
}

export default class HeadingSuggestPlugin extends Plugin {
    settings: PluginSettings

    async onload(): Promise<void> {
        await this.loadSettings();
        this.addCommand({
            id: "rename-heading",
            name: "Rename Heading",
            icon: "plus-square",
            // editorCallback: (editor: Editor, view: MarkdownView) => this.collectCurrentNoteAttachments(editor, view),
            callback: async ()=> {
                await this.renameHeadings();
            },
        });
        this.addCommand({
            id: "verify-heading",
            name: "Verify Heading",
            icon: "plus-square",
            // editorCallback: (editor: Editor, view: MarkdownView) => this.collectCurrentNoteAttachments(editor, view),
            callback: async ()=> {
                await this.verifyHeadings();
            },
        });
        // this.addCommand({
        //     id: "nlp-dates",
        //     name: "Parse natural language date",
        //     callback: () => getParseCommand(this, "replace"),
        //     hotkeys: [],
        // });
        //
        //
        // this.addCommand({
        //     id: "nlp-picker",
        //     name: "Date picker",
        //     checkCallback: (checking: boolean) => {
        //         if (checking) {
        //             return !!this.app.workspace.getActiveViewOfType(MarkdownView);
        //         }
        //         new DatePickerModal(this.app, this).open();
        //     },
        //     hotkeys: [],
        // });

        // this.addSettingTab(new NLDSettingsTab(this.app, this));
        // this.registerObsidianProtocolHandler("nldates", this.actionHandler.bind(this));
        this.registerEditorSuggest(new HeadingSuggest(this.app, this));
        // add settings tab
        this.addSettingTab(new SettingTab(this.app, this));
        // this.app.workspace.onLayoutReady(() => {
        //     // initialize the parser when layout is ready so that the correct locale is used
        //     this.parser = new NLDParser();
        // });
    }

    onunload(): void {
        console.log("Unloading heading suggest plugin");
    }

    async verifyHeadings() {
        const headingSuggestion = new HeadingSuggest(this.app, this);
        headingSuggestion.getHeadings(true);
        new Notice(`done verify! see popup or console for details`);
        console.warn(`done verify! see popup or console for details`);
    }

    async renameHeadings() {

        const mdView = this.app.workspace.getActiveViewOfType(MarkdownView);
        if (!mdView) return false;
        if (mdView.editor == undefined) return false;
        const doc = mdView.editor;

        const cursorPosition = doc.getCursor();
        const currentLineContent = doc.getLine(cursorPosition.line);
        if (!currentLineContent.startsWith("#")) {
            new Notice("current line is not a heading.");
            return false; // 所在行如果不是标题则返回
        }
        const oldHeading = stripLeft(currentLineContent, "#").trim();
        const renamingUI: Modal = new RenamingUI(this.app, this, oldHeading);
        const newHeading = await renamingUI.open();
        console.log(newHeading);
        // const oldHeading = "投资交易业务知识学习";
        // const newHeading = "财经投资业务知识学习";
        // let headingSuggestions: string[] = [];

        const markdownFiles: TFile[] = [];
        const startLocation = this.settings.vaultStartLocation.trim();
        const folderOrFile = this.app.vault.getAbstractFileByPath(startLocation);
        if (folderOrFile instanceof TFile) {
            markdownFiles.push(folderOrFile);
        } else if (folderOrFile instanceof TFolder) {
            Vault.recurseChildren(folderOrFile, (file => {
                if (file instanceof TFile && file.extension === "md") {
                    markdownFiles.push(file);
                }
            }));
        }

        for (const markFile of markdownFiles) {
            // let ignored = false;
            // for (const ignoredSuffix of this.settings.ignoredSuffixArray) {
            //     if (markFile.path.endsWith(ignoredSuffix)) {
            //         ignored = true;
            //         break;
            //     }
            // }
            // if (ignored) break;

            if (this.app.metadataCache.getFileCache(markFile) && this.app.metadataCache.getFileCache(markFile).headings) {
                const cachedHeadings = this.app.metadataCache.getFileCache(markFile).headings;
                if (cachedHeadings) {
                    const headingsToRename = cachedHeadings.filter(heading => heading.heading === oldHeading);
                    for (const headingToRename of headingsToRename) {
                        const headingStartOffset = headingToRename.position.start.offset;
                        const headingEndOffset = headingToRename.position.end.offset;
                        let fileContent = await this.app.vault.read(markFile);
                        fileContent = fileContent.slice(0, headingStartOffset) + ("#".repeat(headingToRename.level) + ` ${newHeading}`) + fileContent.slice(headingEndOffset);
                        await this.app.vault.adapter.write(markFile.path, fileContent);
                    }
                }
            }

        }
        // markdownFiles.forEach((markFile: TFile) => {
        //     for (const ignoredSuffix of this.settings.ignoredSuffixArray) {
        //         if (markFile.path.endsWith(ignoredSuffix)) {
        //             return null;
        //         }
        //     }
        //     const content = await this.app.vault.read(markdownFile);
        //     // if (this.app.metadataCache.getFileCache(markFile) && this.app.metadataCache.getFileCache(markFile).headings) {
        //     //     const cachedHeadings = this.app.metadataCache.getFileCache(markFile).headings;
        //     //     const upLevelHeadingsMap = this.getUpLevelHeadingRecursively(cachedHeadings);
        //     //     upLevelHeadingsMap.forEach((headingCacheArray, keyHeading) => {
        //     //         const reversedArray = headingCacheArray.reverse();
        //     //         const upLevelHeadingsText: string[] = reversedArray.map(v => "#".repeat(v.level) + ` ${v.heading}`);
        //     //         this.upLevelHeadingSuggestions.set("#".repeat(keyHeading.level) + ` ${keyHeading.heading}`, upLevelHeadingsText);
        //     //     });
        //     //     // console.log(upLevelHeadingsMap);
        //     //     if (cachedHeadings){
        //     //         headingSuggestions = headingSuggestions.concat(cachedHeadings.map((v) => {
        //     //             // return  "#".repeat(v.level) + ` ${v.heading} (${markFile.path})`;
        //     //             return  "#".repeat(v.level) + ` ${v.heading}`; // TODO: 最好加一个hint，但是去重要手动做
        //     //         }));
        //     //     }
        //     // }
        // });
    }
    async loadSettings(): Promise<void> {
        this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
    }

    async saveSettings(): Promise<void> {
        await this.saveData(this.settings);
    }
}

class SettingTab extends PluginSettingTab {
    plugin: HeadingSuggestPlugin;

    constructor(app: App, plugin: HeadingSuggestPlugin) {
        super(app, plugin);
        this.plugin = plugin;
    }

    arraymove<T>(
        arr: T[],
        fromIndex: number,
        toIndex: number
    ): void {
        if (toIndex < 0 || toIndex === arr.length) {
            return;
        }
        const element = arr[fromIndex];
        arr[fromIndex] = arr[toIndex];
        arr[toIndex] = element;
    }

    display(): void {
        const {containerEl} = this;
        containerEl.empty();
        this.containerEl.createEl("h2", { text: "General Settings" });

        new Setting(containerEl)
            .setName('VaultStartLocation')
            .setDesc('collect the headers start from here.')
            .addText(text => text
                .setPlaceholder('')
                .setValue(this.plugin.settings.vaultStartLocation)
                .onChange(async (value) => {
                        this.plugin.settings.vaultStartLocation = value;
                        await this.plugin.saveSettings();
                    }
                ));
        new Setting(containerEl)
            .setName('IngoredHeaderList')
            .setDesc('headers that should be ignored.')
            .addText(text => text
                .setPlaceholder('')
                .setValue(this.plugin.settings.ingoredHeaders.join(","))
                .onChange(async (value) => {
                        this.plugin.settings.ingoredHeaders = value.split(",");
                        await this.plugin.saveSettings();
                    }
                ));
        // new Setting(containerEl)
        //     .setName('Location')
        //     .setDesc('set the root location to merge recursively.')
        //     // .setClass('long-description-setting-item')
        //     .addTextArea(text => text
        //         .setPlaceholder('1_Inbox/Diary/2023/2023-07')
        //         .setValue(this.plugin.settings.location)
        //         .onChange(async (value) => {
        //                 this.plugin.settings.location = value
        //                 await this.plugin.saveSettings()
        //             }
        //         ))
        //
        // new Setting(containerEl)
        //     .setName('Output')
        //     .setDesc('set the output location.')
        //     .addTextArea(text => text
        //         .setPlaceholder('1_Inbox/Diary/output.md')
        //         .setValue(this.plugin.settings.output)
        //         .onChange(async (value) => {
        //                 this.plugin.settings.output = value
        //                 await this.plugin.saveSettings()
        //             }
        //         ))
        //
        // new Setting(containerEl)
        //     .setName('Enabled')
        //     .setDesc('write "true" or "false" to enable/disable the job.')
        //     .addTextArea(text => text
        //         .setPlaceholder('true')
        //         .setValue(this.plugin.settings.enabled)
        //         .onChange(async (value) => {
        //                 this.plugin.settings.enabled = value
        //                 await this.plugin.saveSettings()
        //             }
        //         ))

        // new Setting(containerEl)
        //     .setName('Populate empty title')
        //     .setDesc('toggle to populate empty title.')
        //     .addToggle(toggle => toggle
        //         .setValue(this.plugin.settings.populateEmptyTitle)
        //         .onChange(async (value) => {
        //                 this.plugin.settings.populateEmptyTitle = value
        //                 await this.plugin.saveSettings()
        //             }
        //         ))
        //
        // new Setting(containerEl)
        //     .setName('Make title links or not')
        //     .setDesc('toggle to make title links.')
        //     .addToggle(toggle => toggle
        //         .setValue(this.plugin.settings.titleLinks)
        //         .onChange(async (value) => {
        //                 this.plugin.settings.titleLinks = value
        //                 await this.plugin.saveSettings()
        //             }
        //         ))
    }
}
